import { HttpService } from './../../base/services/http.service';
import { LockService } from './../../base/services/lock.service';
import { WXApp, wxLiteConfig, wxConfig } from './wx.definition';
import { Injectable } from '@nestjs/common';

interface TokenModel {
    access_token: string;
    expires_in: number;
    createAt: Date;
    endAt: Date;
}

interface AccessTokenReqParams {
    grant_type: string;
    appid: string;
    secret: string;
}

@Injectable()
export abstract class TokenStorage {
    // 2小时有效时间 提前10min刷新
    private static pretime: number = 1000 * 10;

    private token: TokenModel;
    abstract wxApp: WXApp;

    constructor(private lock: LockService, private http: HttpService) {}

    private isTokenAlive(): boolean {
        return (
            this.token &&
            this.token.endAt.getTime() > Date.now() + TokenStorage.pretime
        );
    }

    public async genToken(): Promise<string> {
        let locker = await this.lock.lock('fetch-token');
        try {
            if (this.isTokenAlive()) return this.token.access_token;

            let params: AccessTokenReqParams = {
                grant_type: 'client_credential',
                appid: this.wxApp.app_id,
                secret: this.wxApp.app_secret,
            };

            let tkMoodel: TokenModel = await this.http.get(
                'https://api.weixin.qq.com/cgi-bin/token',
                params,
            );
            // console.log(text, text.access_token);

            // let tkMoodel = <TokenModel>JSON.parse(text);
            tkMoodel.createAt = new Date();
            tkMoodel.endAt = new Date(Date.now() + 1000 * tkMoodel.expires_in);
            this.token = tkMoodel;

            console.log(`获取到access_token: `, tkMoodel);
            return this.token.access_token;
        } finally {
            await locker.release();
        }
    }
}

@Injectable()
export class WxliteTokenStorage extends TokenStorage {
    wxApp = wxLiteConfig;
}

export class WxTokenStorage extends TokenStorage {
    wxApp = wxConfig;
}
